home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / smaltalk.lha / smalltalk-1.1.1 / mstcint.c < prev    next >
C/C++ Source or Header  |  1991-09-12  |  17KB  |  664 lines

  1. /***********************************************************************
  2.  *
  3.  *    C - Smalltalk Interface module
  4.  *
  5.  ***********************************************************************/
  6.  
  7. /***********************************************************************
  8.  *
  9.  * Copyright (C) 1990, 1991 Free Software Foundation, Inc.
  10.  * Written by Steve Byrne.
  11.  *
  12.  * This file is part of GNU Smalltalk.
  13.  *
  14.  * GNU Smalltalk is free software; you can redistribute it and/or modify it
  15.  * under the terms of the GNU General Public License as published by the Free
  16.  * Software Foundation; either version 1, or (at your option) any later 
  17.  * version.
  18.  * 
  19.  * GNU Smalltalk is distributed in the hope that it will be useful, but WITHOUT
  20.  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
  21.  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  22.  * more details.
  23.  * 
  24.  * You should have received a copy of the GNU General Public License along with
  25.  * GNU Smalltalk; see the file COPYING.  If not, write to the Free Software
  26.  * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  
  27.  *
  28.  ***********************************************************************/
  29.  
  30.  
  31. /*
  32.  *    Change Log
  33.  * ============================================================================
  34.  * Author      Date       Change 
  35.  * sbyrne     4 Jun 89      Added Smalltalk data conversion type.
  36.  *
  37.  * sbyrne    29 May 89      Created.
  38.  *
  39.  */
  40.  
  41. /* Define this to enable initialization of the SunView hacks in the
  42.    ./examples directory */
  43. /* #define SUN_WIN_HACKS */
  44.  
  45. #include "mst.h"
  46. #include "mstinterp.h"
  47. #include "mstdict.h"
  48. #include "mstoop.h"
  49. #include "mstsym.h"
  50.  
  51. #define ARG_VEC_SIZE        20 /* 20 ints, 10 longs or ptrs, 5 dbls */
  52.  
  53.  
  54. typedef enum {
  55.   intAlign,
  56.   longAlign,
  57.   ptrAlign,
  58.   doubleAlign
  59. } AlignmentType;
  60.  
  61. typedef enum {            /* types for C parameters */
  62.   unknownType,            /* when there is no type a priori */
  63.   charType,
  64.   stringType,
  65.   stringOutType,        /* for things that modify string params */
  66.   symbolType,
  67.   byteArrayType,
  68.   intType,
  69.   longType,
  70.   doubleType,
  71.   voidType,            /* valid only as a return type */
  72.   variadicType,            /* for parameters, this param is an array
  73.                    to be interpreted as arguments.  Note that
  74.                    only simple conversions are performed in
  75.                    this case. */
  76.   cObjectType,            /* a C object is being passed */
  77.   smalltalkType            /* no conversion to-from C...C sees this
  78.                    as "void *".  */
  79. } CDataType;
  80.  
  81. typedef struct CFuncDescriptorStruct {
  82.   OBJ_HEADER;
  83.   OOP        cFunction;
  84.   OOP        cFunctionName;
  85.   OOP        returnType;
  86.   OOP        numFixedArgs;
  87.   OOP        argTypes[1];    /* variable length, really numFixedArgs long */
  88. } *CFuncDescriptor;
  89.  
  90. typedef struct SymbolTypeMapStruct {
  91.   OOP        *symbol;
  92.   CDataType    type;
  93. } SymbolTypeMap;
  94.  
  95. typedef struct StringInfoStruct {
  96.   Byte        *cString;
  97.   OOP        stringOOP;
  98.   CDataType    returnedType;
  99. } StringInfo;
  100.  
  101. typedef union CParamUnionUnion {
  102.   int        intVal;
  103.   long        longVal;
  104.   voidPtr    ptrVal;
  105.   double    doubleVal;
  106.   int        valueVec[sizeof(double) / sizeof(int)];
  107. } CParamUnion;
  108.  
  109. typedef struct     CFuncInfoStruct {
  110.   char        *funcName;
  111.   void        (*funcAddr)();
  112. } CFuncInfo;
  113.  
  114. void                defineCFunc();
  115.  
  116. static void             pushObj(), callCFunction(),
  117.                 badType(), pushSmalltalkObj();
  118. static CDataType         getCType();
  119. static CFuncDescriptor         getCFuncDescriptor();
  120. static OOP            classifyTypeSymbol();
  121.  
  122. static CFuncInfo        cFuncInfo[100], *cFuncIndex = cFuncInfo;
  123. static int            cArgVec[ARG_VEC_SIZE];
  124. static int            *cArg;
  125. static StringInfo        stringInfo[ARG_VEC_SIZE], *sip;
  126. /* printable names for corresponding C types */
  127. static char            *cTypeName[] = {
  128.   "void?",            /* unknownType */
  129.   "char",            /* charType */
  130.   "char *",            /* stringType */
  131.   "char *",            /* stringType */
  132.   "char *",            /* symbolType */
  133.   "char *",            /* byteArrayType */
  134.   "int",            /* intType */
  135.   "long",            /* longType */
  136.   "double",            /* doubleType */
  137.   "void?",            /* voidType */
  138.   "var args?",            /* variadicType */
  139.   "void *",            /* cObjectType */
  140.   "void *",            /* smalltalkType */
  141. };
  142.  
  143. static SymbolTypeMap    symbolTypeMap[] = {
  144.   &unknownSymbol, unknownType,
  145.   &charSymbol, charType,
  146.   &stringSymbol, stringType,
  147.   &stringOutSymbol, stringOutType,
  148.   &symbolSymbol, symbolType,
  149.   &byteArraySymbol, byteArrayType,
  150.   &intSymbol, intType,
  151.   &longSymbol, longType,
  152.   &doubleSymbol, doubleType,
  153.   &voidSymbol, voidType,
  154.   &variadicSymbol, variadicType,
  155.   &cObjectSymbol, cObjectType,
  156.   &smalltalkSymbol, smalltalkType,
  157.   nil, unknownType
  158. };
  159.  
  160. /* the arg vec pointer must be = 0 mod alignments[align] */
  161. /* This is quite likely to be machine dependent.  Currently it is set up
  162.  * to work correctly on sun2's, sun3's and sun4's */
  163. static int         alignments[] = {
  164.   sizeof(int),            /* intType */
  165.   sizeof(long),            /* longType */
  166.   sizeof(voidPtr),        /* ptrType */
  167.   DOUBLE_ALIGNMENT        /* doubleType */
  168. };
  169.  
  170. static int        typeSizes[] = {
  171.   sizeof(int),            /* intType */
  172.   sizeof(long),            /* longType */
  173.   sizeof(voidPtr),        /* ptrType */
  174.   sizeof(double)        /* doubleType */
  175. };
  176.  
  177. /*
  178.  *    void marli(n)
  179.  *
  180.  * Description
  181.  *
  182.  *    Test/example C function.
  183.  *
  184.  * Inputs
  185.  *
  186.  *    n     : number of times to emit message.
  187.  *
  188.  */
  189. void marli(n)
  190. int n;
  191. {
  192.   int        i;
  193.  
  194.   for (i = 0; i < n; i++) {
  195.     printf("Marli loves Steve!!!\n");
  196.   }
  197. }
  198.  
  199. void initCFuncs()
  200. {
  201.   extern void marli(), windowLoop();
  202.   extern char *jeff(), *getAttrName();
  203.   extern voidPtr *getAttrValue();
  204.   extern void window_create();
  205.   extern int system();
  206.   extern char *getenv();
  207.  
  208.   defineCFunc("system", system);
  209.   defineCFunc("getenv", getenv);
  210.   defineCFunc("marli", marli);
  211. #ifdef SUN_WIN_HACKS
  212.   defineWindowFuncs();
  213. #endif /* SUN_WIN_HACKS */
  214.  
  215. #ifdef notdefined
  216.   defineCFunc("jeff", jeff);
  217.   defineCFunc("getAttrName", getAttrName);
  218.   defineCFunc("getAttrValue", getAttrValue);
  219. #endif
  220. }
  221.  
  222. void defineCFunc(funcName, funcAddr)
  223. char    *funcName;
  224. void    (*funcAddr)();
  225. {
  226.   cFuncIndex->funcName = funcName;
  227.   cFuncIndex->funcAddr = funcAddr;
  228.   cFuncIndex++;
  229. }
  230.  
  231. void (*lookupFunction(funcName))()
  232. char    *funcName;
  233. {
  234.   CFuncInfo    *fip;
  235.  
  236.   for (fip = cFuncInfo; fip < cFuncIndex; fip++) {
  237.     if (strcmp(funcName, fip->funcName) == 0) {
  238.       return (fip->funcAddr);
  239.     }
  240.   }
  241.   return (nil);
  242. }
  243.  
  244.  
  245.  
  246. /*
  247.  *    void invokeCRoutine(numArgs, methodOOP)
  248.  *
  249.  * Description
  250.  *
  251.  *    Invokes a C routine.  The Smalltalk arguments have been popped off the
  252.  *    Smalltalk stack when this routine returns.
  253.  *
  254.  * Inputs
  255.  *
  256.  *    numArgs: 
  257.  *        
  258.  *    methodOOP: 
  259.  *        
  260.  *
  261.  */
  262. void invokeCRoutine(numArgs, methodOOP)
  263. long    numArgs;
  264. OOP    methodOOP;
  265. {
  266.   CFuncDescriptor desc;
  267.   CDataType    cType;
  268.   OOP        oop; /* oopArgVec[32]; */
  269.   Byte        *stringArg;
  270.   int        i;
  271.  
  272.   cArg = cArgVec;
  273.   
  274.   desc = getCFuncDescriptor(methodOOP);
  275.  
  276.   sip = stringInfo;
  277.  
  278.   for (i = 0; i < numArgs; i++) {
  279.     oop = stackAt(numArgs - i - 1);
  280.     cType = getCType(desc, i);
  281.     pushSmalltalkObj(oop, cType);
  282.   }
  283.  
  284.   popNOOPs(numArgs);
  285.  
  286.   callCFunction(desc);
  287.  
  288.   /* Fixup all returned string variables */
  289.   for ( ; sip-- != stringInfo; ) {
  290.     if (sip->returnedType == stringOutType) {
  291.       setOOPString(sip->stringOOP, sip->cString);
  292.     }
  293.     free(sip->cString);
  294.   }
  295. }
  296.  
  297. static CFuncDescriptor getCFuncDescriptor(methodOOP)
  298. OOP    methodOOP;
  299. {
  300.   OOP        associationOOP, descOOP;
  301.  
  302.   associationOOP = methodLiteralExt(methodOOP, 0);
  303.   descOOP = associationValue(associationOOP);
  304.   return ((CFuncDescriptor)oopToObj(descOOP));
  305. }
  306.  
  307. static CDataType getCType(desc, index)
  308. CFuncDescriptor desc;
  309. int    index;
  310. {
  311.   if (index < toInt(desc->numFixedArgs)) {
  312.     return ((CDataType)toInt(desc->argTypes[index]));
  313.   } else {
  314.     return (unknownType);
  315.   }
  316. }
  317.  
  318. static void pushSmalltalkObj(oop, cType)
  319. OOP    oop;
  320. CDataType cType;
  321. {
  322.   OOP        class;
  323.   int        i;
  324.   CParamUnion    u;
  325.  
  326.   if (cArg - cArgVec >= ARG_VEC_SIZE) {
  327.     errorf("Attempt to push more than %d ints; extra parameters ignored",
  328.        ARG_VEC_SIZE);
  329.     return;
  330.   }
  331.  
  332.   if (isInt(oop)) {
  333.     class = integerClass;
  334.   } else if (oop == trueOOP || oop == falseOOP) {
  335.     class = booleanClass;
  336.   } else {
  337.     class = oopClass(oop);
  338.   }
  339.  
  340.   if (cType == smalltalkType) {
  341.     u.ptrVal = (voidPtr)oop;
  342.     pushObj(&u, ptrAlign);
  343.   } else if (class == integerClass) {
  344.     if (cType == longType || cType == unknownType) {
  345.       u.longVal = toInt(oop);
  346.       pushObj(&u, longAlign);
  347.     } else if (cType == intType || cType == charType) {
  348.       u.intVal = toInt(oop);
  349.       pushObj(&u, intAlign);
  350.     } else {
  351.       badType("Integer", cType);
  352.     }
  353.   } else if (class == booleanClass) {
  354.     if (cType == intType || cType == charType || cType == unknownType) {
  355.       u.intVal = (oop == trueOOP);
  356.       pushObj(&u, intAlign);
  357.     } else if (cType == longType) {
  358.       u.longVal = (oop == trueOOP);
  359.       pushObj(&u, longAlign);
  360.     } else {
  361.       badType("Boolean", cType);
  362.     }
  363.   } else if (class == charClass) {
  364.     if (cType == charType || cType == unknownType) {
  365.       u.intVal = charOOPValue(oop);
  366.       pushObj(&u, intAlign);
  367.     } else {
  368.       badType("Character", cType);
  369.     }
  370.   } else if (class == stringClass) {
  371.     if (cType == stringType || cType == stringOutType
  372.     || cType == unknownType) {
  373.       if (sip - stringInfo >= ARG_VEC_SIZE) {
  374.     errorf("Too many string arguments, max is %d.  Extra ignored",
  375.            ARG_VEC_SIZE);
  376.       }
  377.       sip->cString = toCString(oop);
  378.       u.ptrVal = (voidPtr)sip->cString;
  379.       sip->stringOOP = oop;
  380.       sip->returnedType = cType;
  381.       sip++;
  382.       pushObj(&u, ptrAlign);
  383.     } else {
  384.       badType("String", cType);
  385.     }
  386.   } else if (class == symbolClass) {
  387.     if (cType == symbolType || cType == stringType || cType == unknownType) {
  388.       if (sip - stringInfo >= ARG_VEC_SIZE) {
  389.     errorf("Too many string arguments, max is %d.  Extra ignored",
  390.            ARG_VEC_SIZE);
  391.       }
  392.       sip->cString = toCString(oop);
  393.       u.ptrVal = (voidPtr)sip->cString;
  394.       sip->stringOOP = oop;
  395.       sip->returnedType = cType;
  396.       sip++;
  397.       pushObj(&u, ptrAlign);
  398.     } else {
  399.       badType("Symbol", cType);
  400.     }
  401.   } else if (class == byteArrayClass) {
  402.     if (cType == byteArrayType || cType == unknownType) {
  403.       if (sip - stringInfo >= ARG_VEC_SIZE) {
  404.     errorf("Too many string arguments, max is %d.  Extra ignored",
  405.            ARG_VEC_SIZE);
  406.       }
  407.       sip->cString = toByteArray(oop);
  408.       u.ptrVal = (voidPtr)sip->cString;
  409.       sip->stringOOP = oop;
  410.       sip->returnedType = cType;
  411.       sip++;
  412.       pushObj(&u, ptrAlign);
  413.     } else {
  414.       badType("ByteArray", cType);
  415.     }
  416.   } else if (class == floatClass) {
  417.     if (cType == doubleType || cType == unknownType) {
  418.       u.doubleVal = floatOOPValue(oop);
  419.       pushObj(&u, doubleAlign);
  420.     } else {
  421.       badType("Float", cType);
  422.     }
  423.   } else if (class == cObjectClass) { 
  424.     if (cType == cObjectType || cType == unknownType) {
  425.       u.ptrVal = cObjectValue(oop);
  426.       pushObj(&u, ptrAlign);
  427.     } else {
  428.       badType("CObject", cType);
  429.     }
  430.   } else if (class == undefinedObjectClass) {
  431.     switch (cType) {
  432.     case cObjectType:
  433.     case stringType:
  434.     case symbolType:
  435.     case unknownType:
  436.       u.ptrVal = nil;
  437.       pushObj(&u, ptrAlign);
  438.       break;
  439.  
  440.     default:
  441.       badType("UndefinedObject", cType);
  442.     }
  443.   } else if (class == arrayClass) {
  444.     for (i = 1; i <= numOOPs(oopToObj(oop)); i++) {
  445.       pushSmalltalkObj(arrayAt(oop, i), unknownType);
  446.     }
  447.   }
  448.   
  449. }
  450.  
  451. static void pushObj(up, align)
  452. CParamUnion *up;
  453. AlignmentType align;
  454. {
  455.   int i, alignInts;
  456.  
  457.   alignInts = alignments[ENUM_INT(align)] / sizeof(int);
  458.  
  459.   /* Align the stack properly */
  460.   if ((cArg - cArgVec) % alignInts) {
  461.     cArg += alignInts - ((cArg - cArgVec) % alignInts);
  462.   }
  463.   
  464.   for (i = 0; i < typeSizes[ENUM_INT(align)] / sizeof(int); i++) {
  465.     if (cArg - cArgVec >= ARG_VEC_SIZE) {
  466.       errorf("Too many parameters, max = %d.  Extra parameters ignored",
  467.          ARG_VEC_SIZE);
  468.       return;
  469.     }
  470.     *cArg++ = up->valueVec[i];
  471.   }
  472. }
  473.  
  474. static void callCFunction(desc)
  475. CFuncDescriptor desc;
  476. {  
  477.   int        intResult;
  478.   long        longResult;
  479.   double    doubleResult;
  480.   int        (*cFunction)();
  481.   CDataType    returnType;
  482.  
  483.   cFunction = (int (*)())cObjectValue(desc->cFunction);
  484.   returnType = (CDataType)toInt(desc->returnType);
  485.  
  486.   switch (returnType) {
  487.   case voidType:
  488.     (*cFunction)(
  489.       cArgVec[0],  cArgVec[1],  cArgVec[2],  cArgVec[3],
  490.       cArgVec[4],  cArgVec[5],  cArgVec[6],  cArgVec[7],
  491.       cArgVec[8],  cArgVec[9],  cArgVec[10], cArgVec[11],
  492.       cArgVec[12], cArgVec[13], cArgVec[14], cArgVec[15],
  493.       cArgVec[16], cArgVec[17], cArgVec[18], cArgVec[19]);
  494.     break;
  495.   case charType:
  496.   case intType:
  497.     intResult = (*cFunction)(
  498.       cArgVec[0],  cArgVec[1],  cArgVec[2],  cArgVec[3],
  499.       cArgVec[4],  cArgVec[5],  cArgVec[6],  cArgVec[7],
  500.       cArgVec[8],  cArgVec[9],  cArgVec[10], cArgVec[11],
  501.       cArgVec[12], cArgVec[13], cArgVec[14], cArgVec[15],
  502.       cArgVec[16], cArgVec[17], cArgVec[18], cArgVec[19]);
  503.     switch (returnType) {
  504.     case intType: 
  505.       setStackTop(fromInt((long)intResult));
  506.       break;
  507.     case charType:
  508.       setStackTop(charOOPAt((Byte)intResult));
  509.       break;
  510.     }
  511.     break;
  512.  
  513.   case longType:
  514.   case stringType:
  515.   case symbolType:
  516.   case cObjectType:
  517.   case smalltalkType:
  518.     longResult = (*(long (*)())cFunction)(
  519.       cArgVec[0],  cArgVec[1],  cArgVec[2],  cArgVec[3],
  520.       cArgVec[4],  cArgVec[5],  cArgVec[6],  cArgVec[7],
  521.       cArgVec[8],  cArgVec[9],  cArgVec[10], cArgVec[11],
  522.       cArgVec[12], cArgVec[13], cArgVec[14], cArgVec[15],
  523.       cArgVec[16], cArgVec[17], cArgVec[18], cArgVec[19]);
  524.     switch (returnType) {
  525.     case longType:
  526.       setStackTop(fromInt(longResult));
  527.       break;
  528.     case stringType:
  529.       if (longResult == 0) {
  530.     setStackTop(nilOOP);
  531.       } else {
  532.     setStackTop(stringNew((char *)longResult));
  533.       }
  534.       break;
  535.     case symbolType:
  536.       if (longResult == 0) {
  537.     setStackTop(nilOOP);
  538.       } else {
  539.     setStackTop(internString((char *)longResult));
  540.       }
  541.       break;
  542.     case cObjectType:
  543.       if (longResult == 0) {
  544.     setStackTop(nilOOP);
  545.       } else {
  546.     setStackTop(cObjectNew((voidPtr)longResult));
  547.       }
  548.       break;
  549.     case smalltalkType:
  550.       setStackTop((OOP)longResult);
  551.       break;
  552.     }
  553.     break;
  554.  
  555.   case doubleType:
  556.     doubleResult = (*(double (*)())cFunction)(
  557.       cArgVec[0],  cArgVec[1],  cArgVec[2],  cArgVec[3],
  558.       cArgVec[4],  cArgVec[5],  cArgVec[6],  cArgVec[7],
  559.       cArgVec[8],  cArgVec[9],  cArgVec[10], cArgVec[11],
  560.       cArgVec[12], cArgVec[13], cArgVec[14], cArgVec[15],
  561.       cArgVec[16], cArgVec[17], cArgVec[18], cArgVec[19]);
  562.     setStackTop(floatNew(doubleResult));
  563.     break;
  564.  
  565.   default:
  566.     errorf("Invalid C function return type specified, index %d\n",
  567.        returnType);
  568.     break;
  569.   }
  570.  
  571. }
  572.  
  573. static void badType(smalltalkTypeName, cType)
  574. char    *smalltalkTypeName;
  575. CDataType cType;
  576. {
  577.   errorf("Attempt to pass a %s as a %s", smalltalkTypeName,
  578.      cTypeName[ENUM_INT(cType)]);
  579. }
  580.  
  581.  
  582. OOP makeDescriptor(funcNameOOP, returnTypeOOP, argsOOP)
  583. OOP    funcNameOOP, returnTypeOOP, argsOOP;
  584. {
  585.   char        *funcName;
  586.   void        (*funcAddr)();
  587.   int        numArgs, i;
  588.   CFuncDescriptor desc;
  589.  
  590.   funcName = (char *)toCString(funcNameOOP);
  591.   funcAddr = lookupFunction(funcName);
  592.  
  593.   if (argsOOP == nilOOP) {
  594.     numArgs = 0;
  595.   } else {
  596.     numArgs = numOOPs(oopToObj(argsOOP));
  597.   }
  598.  
  599.   /*
  600.    * since these are all either ints or new objects, I'm not moving the
  601.    * oops
  602.    */
  603.   desc = (CFuncDescriptor)newInstanceWith(cFuncDescriptorClass, numArgs);
  604.   desc->cFunction = cObjectNew(funcAddr);
  605.   desc->cFunctionName = stringNew(funcName);
  606.   desc->numFixedArgs = fromInt(numArgs);
  607.   desc->returnType = classifyTypeSymbol(returnTypeOOP);
  608.   for (i = 1; i <= numArgs; i++) {
  609.     desc->argTypes[i - 1] = classifyTypeSymbol(arrayAt(argsOOP, i));
  610.   }
  611.  
  612.   return (allocOOP(desc));
  613. }
  614.  
  615. static OOP classifyTypeSymbol(symbolOOP)
  616. OOP    symbolOOP;
  617. {
  618.   SymbolTypeMap    *sp;
  619.   Byte        *symbolName;
  620.  
  621.   for (sp = symbolTypeMap; sp->symbol != nil; sp++) {
  622.     if (*sp->symbol == symbolOOP) {
  623.       return (fromInt(sp->type));
  624.     }
  625.   }
  626.  
  627.   symbolName = toCString(symbolOOP); /* yeah yeah...but they have the same
  628.                         representation! */
  629.   errorf("Unknown data type symbol: %s", symbolName);
  630.  
  631.   return (fromInt(unknownType));
  632. }
  633.  
  634. /*
  635.  *    void restoreCFuncDescriptor(cFuncDescOOP)
  636.  *
  637.  * Description
  638.  *
  639.  *    This routine is called during image loading to restore a C function
  640.  *    descriptor pointer.  This is because between the time that the image
  641.  *    was made and now, the executable image may have changed, so any
  642.  *    reference to the C function address may be invalid.  We therefore just
  643.  *    perform the function lookup again and use that value.
  644.  *
  645.  * Inputs
  646.  *
  647.  *    cFuncDescOOP: 
  648.  *        A C function descriptor object to be adjusted.  Contains the
  649.  *        name of the function to be looked up.
  650.  *
  651.  */
  652. void restoreCFuncDescriptor(cFuncDescOOP)
  653. OOP    cFuncDescOOP;
  654. {
  655.   CFuncDescriptor desc;
  656.   void        (*funcAddr)();
  657.   char        *funcName;
  658.  
  659.   desc = (CFuncDescriptor)oopToObj(cFuncDescOOP);
  660.   funcName = (char *)toCString(desc->cFunctionName);
  661.   funcAddr = lookupFunction(funcName);
  662.   setCObjectValue(desc->cFunction, funcAddr);
  663. }
  664.